import os
import sys
#store by being pickled.
#any Djoser property that isn't a primitive should be handled separately


class MeringueProjectShell():
	projectName = None
	widgets = None
	title = ''
	width=500
	height=500
	window=None
	def __init__(self):
		self.widgets = []
		self.window = MeringueProjectWindow()
	
	def check(self):
		wnamesseen={}
		for w in self.widgets:
			if w.widgetName in wnamesseen:
				raise 'Duplicate widget name:%s'%w.widgetName
			wnamesseen[w.widgetName]=True

class MeringueProjectWindow():
	pyrindProperties = None
	pyrindClassName = 'RWindow'
	def __init__(self):
		self.pyrindProperties = {}
	def generatePythonCode(self):
		if not self.pyrindProperties: return []
		propstr = []
		for prop in self.pyrindProperties:
			propstr.append('%s=%s'%(prop, self.pyrindProperties[prop].__repr__()))
		propstr = join(propstr,',')
		aout = ['w.set_many(%s)'% propstr]
		return aout
	
class MeringueProjectWidgetBase():
	coordLeft = 0
	coordTop = 0
	widgetName = None
	pyrindProperties = None
	pyrindClassName = None
	def __init__(self, widgetName):
		self.widgetName = widgetName
		self.pyrindProperties = {}
	def generatePythonCode(self):
		propstr = []
		for prop in self.pyrindProperties:
			propstr.append('%s=%s'%(prop, self.pyrindProperties[prop].__repr__()))
		propstr = join(propstr,',')
		aout = []
		aout.append('self.%s = pyrind.%s(parent=topframe, %s)'%(self.widgetName, self.pyrindClassName, propstr))
		aout.append('self.%s.add(position=(%d,%d))'%(self.widgetName, self.coordLeft,self.coordTop))
		return aout
	def genEventHandler(self):
		return False

class MeringueProjectButton(MeringueProjectWidgetBase):
	pyrindClassName = 'RButton'
	hasOnclickBinding = False
	def genEventHandler(self):
		return self.hasOnclickBinding == True

class MeringueProjectInput(MeringueProjectWidgetBase):
	pyrindClassName = 'RInput'
class MeringueProjectCheckbox(MeringueProjectWidgetBase):
	pyrindClassName = 'RCheckbox'
class MeringueProjectField(MeringueProjectWidgetBase):
	pyrindClassName = 'RField'
class MeringueProjectCheckbox(MeringueProjectWidgetBase):
	pyrindClassName = 'RCheckbox'
class MeringueProjectLabel(MeringueProjectWidgetBase):
	pyrindClassName = 'RLabel'
class MeringueProjectListbox(MeringueProjectWidgetBase):
	pyrindClassName = 'RListbox'


def join(a, s): return s.join(a)
exporttemplate='''
#Generated by Meringue. Do not edit this file.
#Changes to this file will not be saved!
from importpyrind import pyrind
import $CODEMODNAME$
codecallmodule = $CODEMODNAME$

class Application_$APPNAME$():
	def __init__(self,w):
		$LAYOUTCODE$
		
	$EVENTBINDINGS$

if __name__=='__main__':
	app = Application_$APPNAME$(pyrind.RWindow())
'''		
newline = '\r\n' if sys.platform=='win32' else '\n'
def renderShellClassToPython(projectShell, codemodulename):
	projectShell.check()
	bindings = []
	codefile = []
	
	aout = []
	aout.append('self.window = w')
	aout.append('w.title=%s' % projectShell.title.__repr__())
	aout.extend(projectShell.window.generatePythonCode() )
	aout.append('topframe = w.begin_frame(fill=True, resizable=True)')
	aout.append('self.window._basecontrol.geometry("%dx%d")' %(projectShell.width, projectShell.height))
	for widget in projectShell.widgets:
		aout.extend( widget.generatePythonCode() )
		if widget.genEventHandler():
			aout.append('self.%s.onclick=self.%s_onclick'%(widget.widgetName,widget.widgetName))
			bindings.append( 'def %s_onclick(self):'%widget.widgetName)
			bindings.append('\tcodecallmodule.%s_onclick(self)'%widget.widgetName)
			
	aout.append('codecallmodule.onload(self)')
	aout.append('w.end_frame()')
	aout.append('w.start()')
	
	
	layoutcode = join(aout, newline+'\t\t')
	bindingscode = join(bindings, newline+'\t')
	out = exporttemplate
	out = out.replace('$APPNAME$', projectShell.projectName)
	out = out.replace('$CODEMODNAME$', codemodulename)
	out = out.replace('$LAYOUTCODE$', layoutcode)
	out = out.replace('$EVENTBINDINGS$', bindingscode)
	return out


def renderCodeImplToPython(projectShell, filename):
	strAvailObjects = '#Available objects:'
	def drawAvailObjectsList():
		lw = []
		sortedw = sorted([(widget.pyrindClassName, widget.widgetName, widget.genEventHandler()) for widget in projectShell.widgets])
		sortedw.insert(0, ('RWindow', 'window',False))	
		for wclass, wname, hasevent in sortedw:
			s='# app.%s\t\t(%s)'%(wname, wclass)
			if hasevent: s+= ' *'
			lw.append(s)
		return lw
	
	if not os.path.exists(filename):
		aout = []
		aout.append('#implementation of project %s'%projectShell.title)
		aout.append('')
		aout.append(strAvailObjects)
		
		aout.extend(drawAvailObjectsList())
		aout.append(''); aout.append('')
		aout.append('def onload(app):')
		aout.append('\tpass')
		aout.append('')
		for widget in projectShell.widgets:
			if widget.genEventHandler():
				aout.append('def %s_onclick(app):'%widget.widgetName)
				aout.append('\tpass')
				aout.append('')
		f=open(filename,'wb')
		f.write( join(aout, newline))
		f.close()
	else:
		#parse and recreate file, leaving user's code intact
		f=open(filename,'rb')
		txt = f.read()
		f.close()
		#create a list of functions seen
		lines = txt.replace('\r\n','\n').split('\n')
		fnnames = {}
		for line in lines:
			linepts =  line.strip().split()
			if not linepts: continue
			if linepts[0] == 'def' and len(linepts)>1:
				fnname = linepts[1].split('(')[0]
				fnnames[fnname]=True
		#now see if any of these are missing
		aout=[]
		if 'onload' not in fnnames:
			aout.append('def onload(app):'); aout.append('\tpass')
		for widget in projectShell.widgets:
			if widget.genEventHandler():
				if ('%s_onclick'%widget.widgetName) not in fnnames:
					aout.append('def %s_onclick(app):'%widget.widgetName)
					aout.append('\tpass')
					aout.append('')
		
		#replace the "avail objects". (but if it's been deleted, whatever)
		newtxt = []
		inAvailObjects=False
		for line in lines:
			if line.strip()==strAvailObjects:
				newtxt.append( strAvailObjects)
				newtxt.extend( drawAvailObjectsList() )
				inAvailObjects=True
			elif inAvailObjects and line.strip().startswith('# app.'):
				pass
			else:
				inAvailObjects=False
				newtxt.append( line)
		if aout:
			newtxt.append('')
			newtxt.extend(aout)
		f=open(filename,'wb')
		f.write( join(newtxt, newline))
		f.close()
		

if __name__=='__main__':
	#test this.
	proj = MeringueProjectShell()
	proj.projectName = 'test'
	proj.title = 'Heytesting'
	proj.width=500
	proj.height=400
	proj.window.pyrindProperties['bgcolor']=(255,0,0)
	btnshell = MeringueProjectButton('button1')
	btnshell.coordTop = 34
	btnshell.coordLeft = 34
	btnshell.pyrindProperties['text'] = 'why hello there'
	btnshell.hasOnclickBinding = True
	proj.widgets.append(btnshell)
	print renderShellClassToPython(proj, 'codemodname')
	
	